package midend.IR_Instruction;

import midend.IR_Value.IR_BaseBlock;
import midend.IR_Value.IR_FuncBlock;
import midend.IR_Value.IR_Value;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Branch_Instruction extends Instruction{

    // false 无条件跳转 true 条件跳转
    private boolean br_type;
    //if
    private IR_BaseBlock block1 = null;
    //else
    private IR_BaseBlock block2 = null;

    public Branch_Instruction(List<IR_Value> op, IR_BaseBlock bb) {
        //这个构造函数里面的  bb是指代的当前的分支指令属于的代码块
        super(op, bb);
        //在分支指令里面 op 对应的操作数实际上就是两个代码块
        if(op.size() == 1){
            //这个是无条件跳转
            br_type = false;
            block1 = (IR_BaseBlock)op.get(0);
        }
        else{
            //这个是有条件跳转  get 0 本质就是读取该跳转的条件
            br_type = true;
            addValue(get_op_index(0));
            block1 = (IR_BaseBlock)op.get(1);
            block2 = (IR_BaseBlock)op.get(2);
        }
    }

    public IR_BaseBlock get_block1() {
        return block1;
    }

    public IR_BaseBlock get_block2() {
        return block2;
    }

    public void setBlock2(IR_BaseBlock block2) {
        this.block2 = block2;
    }

    public void setBlock1(IR_BaseBlock block1) {
        this.block1 = block1;
    }

    public boolean br_type() {
        return br_type;
    }

    public void updateop(int index, IR_Value newValue) {
        if(index == 0){
            set_Op(0, newValue);
        }
    }

    @Override
    public String toString() {
        if(!br_type){
            //无条件跳转
            return "br label %" +
                    block1.get_ValueName();
        }
        //条件跳转
        return "br " + get_op().get(0).get_Type().get_TypeName() + " " +
                get_op().get(0).get_ValueName() + ", label %" +
                this.block1.get_ValueName() +
                ", label %" +
                this.block2.get_ValueName();
    }


    @Override
    public Branch_Instruction clone(IR_BaseBlock block) {
        Branch_Instruction brInstr = null;
        ArrayList<IR_Value> copy_ops = new ArrayList<>();
        if (this.br_type) {
            IR_Value cond = get_op().get(0);
            IR_BaseBlock ifTrueBlock = block1;
            IR_BaseBlock ifFalseBlock = block2;
            if (IR_FuncBlock.cloneMap_Value.containsKey(cond)) {
                cond = IR_FuncBlock.cloneMap_Value.get(cond);
            }
            copy_ops.add(cond);
            if (IR_FuncBlock.cloneMap_Value.containsKey(ifTrueBlock)) {
                ifTrueBlock = (IR_BaseBlock) IR_FuncBlock.cloneMap_Value.get(ifTrueBlock);
            }
            copy_ops.add(ifTrueBlock);
            if (IR_FuncBlock.cloneMap_Value.containsKey(ifFalseBlock)) {
                ifFalseBlock = (IR_BaseBlock) IR_FuncBlock.cloneMap_Value.get(ifFalseBlock);
            }
            copy_ops.add(ifFalseBlock);
            brInstr = new Branch_Instruction(copy_ops, block);
        } else {
            IR_BaseBlock destBlock = block1;
            if (IR_FuncBlock.cloneMap_Value.containsKey(destBlock)) {
                destBlock = (IR_BaseBlock) IR_FuncBlock.cloneMap_Value.get(destBlock);
            }
            copy_ops.add(destBlock);
            brInstr = new Branch_Instruction(copy_ops, block);
        }
        // brInstr.setBasicBlock(block);
        return brInstr;
    }

    public void change_Dest(IR_BaseBlock before, IR_BaseBlock after) {
        if (br_type) {
            if (block1 == before) {
                block1 = after;
            } else if (block2 == after) {
                block2 = after;
            }
        } else {
            if (block1 == before) {
                block1 = after;
            }
        }
    }

}
